package com.idealighter.game.robot.common.cards;

import com.google.common.collect.Lists;

import com.idealighter.game.dictionary.domain.TexapokerRobotRulesDomain;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * . 德州牌型计算器 .
 */
public class DeckPowerCompare extends CardPowerCompare {

  @Override
  public CardCompare rank(List<Card> cards) {
    MapList<CardNumber, Card> numberGroup = getNumberGroup(cards);// 转成Map结构 牌值
    MapList<CardSuit, Card> suitGroup = getSuitGroup(cards);// 转成Map结构 花色
    List<Card> cardsSortedByNumber = getCardsSortedByNumber(cards); // 对牌进行排序
    CardNumber straightFlushNumber = getStraightFlushNumber(suitGroup, 5);
    // Straight flush 同花顺
    if (straightFlushNumber != null) {
      return new DeckCompare(CardType.STRAIGHT_FLUSH, Arrays.asList(straightFlushNumber),
          cardsSortedByNumber);
    }

    CardNumber cardNumberForFour = getCardNumberForCount(4, numberGroup);
    // Four of a kind 4+1
    if (cardNumberForFour != null) {
      return new DeckCompare(CardType.FOUR_OF_A_KIND,
          calculateSameKindTie(4, cardNumberForFour, cardsSortedByNumber), cardsSortedByNumber);
    }

    List<CardNumber> fullHouseCardNumbers = getFullHouse(numberGroup);
    // Full house
    if (fullHouseCardNumbers.size() == 2) {
      return new DeckCompare(CardType.FULL_HOUSE, fullHouseCardNumbers, cardsSortedByNumber);
    }

    // Flush
    CardSuit flushSuit = getFlush(suitGroup, 5);
    if (flushSuit != null) {
      return new DeckCompare(CardType.FLUSH, calculateFlushTie(flushSuit, suitGroup),
          cardsSortedByNumber);
    }

    // Straight
    CardNumber straightNumber = getStraight(numberGroup, 5);
    if (straightNumber != null) {
      return new DeckCompare(CardType.STRAIGHT, Arrays.asList(straightNumber), cardsSortedByNumber);
    }

    // Three of a kind 3+1+1
    CardNumber cardNumberForThree = getCardNumberForCount(3, numberGroup);
    if (cardNumberForThree != null) {
      return new DeckCompare(CardType.THREE_OF_A_KIND,
          calculateSameKindTie(3, cardNumberForThree, cardsSortedByNumber), cardsSortedByNumber);
    }

    // Pair(s) 一对
    CardNumber cardNumberForTwo = getCardNumberForCount(2, numberGroup);
    if (cardNumberForTwo != null) {
      List<CardNumber> pairsCardNumber = getPairs(numberGroup);
      // Two pair
      if (pairsCardNumber.size() >= 2) {
        return new DeckCompare(CardType.TWO_PAIR,
            calculateTwoPairsTie(pairsCardNumber, cardsSortedByNumber), cardsSortedByNumber);
      } else { // One Pair
        return new DeckCompare(CardType.ONE_PAIR,
            calculateSameKindTie(2, cardNumberForTwo, cardsSortedByNumber), cardsSortedByNumber);
      }
    }

    // High Card 单牌
    return new DeckCompare(CardType.HIGH_CARD, bestCardsNumberInList(cardsSortedByNumber),
        cardsSortedByNumber);
  }

  /**
   * 同花顺判断 .
   *
   * @param suitGroup . .
   * @param staightNum . .
   * @return .
   */

  @Override
  public CardNumber getStraightFlushNumber(MapList<CardSuit, Card> suitGroup, int staightNum) {
    CardSuit flushSuit = getFlush(suitGroup, 5);
    if (flushSuit == null) {
      return null;
    }

    List<Card> cards = suitGroup.get(flushSuit);
    List<CardNumber> cardNumbers = cardsToCardNumber(cards);

    return getStraightNumber(cardNumbers, staightNum);
  }

  /**
   * 顺子判断.
   *
   * @param cardNumberList . .
   * @param staightNum . .
   * @return .
   */
  @Override
  public CardNumber getStraightNumber(List<CardNumber> cardNumberList, int staightNum) {
    List<CardNumber> cardNumbers = new ArrayList<>();
    cardNumbers.addAll(cardNumberList);
    CardNumber straightNumber = null;
    int straightCount = 0;
    int prevPower = 0;
    boolean flag = false;
    for (CardNumber cardNumber : cardNumbers) {
      if (cardNumber == CardNumber.ACE) {
        flag = true;
        break;
      }
    }
    if (flag) {
      cardNumbers.add(CardNumber.ONE);
    }
    Collections.sort(cardNumbers, cardNumberComparator);
    for (CardNumber cardNumber : cardNumbers) {
      if (cardNumber.getPower() == prevPower + 1) {
        straightCount++;
        if (straightCount >= staightNum) {
          straightNumber = cardNumber;
        }
      } else {
        straightCount = 1;
      }
      prevPower = cardNumber.getPower();
    }
    return straightNumber;
  }

  /**
   * 各种牌型检测 .
   *
   * @param cards . ->手上的牌 ：包括手牌和公共牌 .
   * @param handCard . .
   * @param domain . .
   */
  public void isHave(List<Card> cards, List<Card> handCard, TexapokerRobotRulesDomain domain) {
    MapList<CardNumber, Card> numberGroup = getNumberGroup(cards);

    if (cards.size() == 2) { // 手牌
      if (isPaired(numberGroup)) {
        domain.setPaired(1);
        domain.setPairedMax(1);
        domain.setPairedMin(1);
        domain.setPairedMy(1);
        return;
      }
    }
    if (isPaired(numberGroup)) {
      domain.setPaired(1);
      if (isPairedMax(cards)) {
        domain.setPairedMax(1);
        domain.setPairedMin(0);
      }
      if (isPairesMin(cards)) {
        domain.setPairedMin(1);
        domain.setPairedMax(0);
      }
      if (pairedMy(cards, handCard)) {
        domain.setPairedMy(1);
      } else {
        domain.setPairedMy(0);
      }
    }
    if (isTwoTwo(numberGroup)) {
      domain.setTwoTwo(1);
      if (isTwoTwoMy(cards, handCard)) {
        domain.setTwoTwoMy(1);
      } else {
        domain.setTwoTwoMy(0);
      }
    }
    if (isThree(numberGroup)) {
      domain.setThree(1);
      if (isThreeMax(cards)) {
        domain.setThreeMax(1);
      } else {
        domain.setThreeMax(0);
      }
      if (isThreeMy(cards, handCard)) {
        domain.setThreeMy(1);
      } else {
        domain.setThreeMy(0);
      }
    }
    if (isFour(numberGroup)) {
      domain.setFour(1);
      if (isFourMy(cards, handCard)) {
        domain.setFourMy(1);
      } else {
        domain.setFourMy(0);
      }
    }
    if (isLongThree(numberGroup)) {
      domain.setLongThree(1);
      if (isLongThreeMy(cards, handCard)) {
        domain.setLongThreeMy(1);
      } else {
        domain.setLongThreeMy(0);
      }
    }
    if (isLongFour(numberGroup)) {
      domain.setLongFour(1);
      if (isLongFourMy(cards, handCard)) {
        domain.setLongFourMy(1);
      } else {
        domain.setLongFourMy(0);
      }
    }
    if (isLongFive(numberGroup)) {
      domain.setLongFive(1);
      if (isLongFiveMy(cards, handCard)) {
        domain.setLongFiveMy(1);
      } else {
        domain.setLongFiveMy(0);
      }
    }
    // if (isLongFourO(cards, handCard)) {
    // domain.setLongFourO(1);
    // }
    MapList<CardSuit, Card> suitGroup = getSuitGroup(cards);
    if (isSameFour(suitGroup)) {
      domain.setSameFour(1);
      if (isSameFourMy(cards, handCard)) {
        domain.setSameFourMy(1);
      } else {
        domain.setSameFourMy(0);
      }
    }
    if (isSameFive(suitGroup)) {
      domain.setSameFive(1);
      if (isSameFiveMy(cards, handCard)) {
        domain.setSameFiveMy(1);
      } else {
        domain.setSameFiveMy(0);
      }
    }
    if (isSameLong(cards)) {
      domain.setSameLong(1);
      if (isSameLongMy(cards, handCard)) {
        domain.setSameLongMy(1);
      } else {
        domain.setSameLongMy(0);
      }
    }
  }


  /**
   * 是否有对子.
   *
   * @return .
   */
  private boolean isPaired(MapList<CardNumber, Card> numberGroup) {
    CardNumber cardNumberForPaired = getCardNumberForCount(2, numberGroup);
    if (cardNumberForPaired != null) {
      return true;
    }
    return false;
  }

  /**
   * 对子是否是最大牌 .
   *
   * @param cards . .
   * @return .
   */
  private boolean isPairedMax(List<Card> cards) {
    return rank(cards).getHandPowerType().getPower() <= CardType.ONE_PAIR.getPower();
  }

  /**
   * 对子中是否是最小牌 .
   *
   * @param cards . .
   * @return .
   */
  private boolean isPairesMin(List<Card> cards) {
    return rank(cards).getHandPowerType().getPower() > CardType.ONE_PAIR.getPower();
  }

  /**
   * 对子中是否有手牌 .
   *
   * @param cards . .
   * @return .
   */
  private boolean pairedMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempcardsGroup = getNumberGroup(tempCard);
    if (isPaired(cardsGroup) && !isPaired(tempcardsGroup)) {
      return true;
    }
    return false;

  }

  /**
   * 是否有两对 .
   *
   * @param cards . .
   * @return .
   */
  private boolean isTwoTwo(MapList<CardNumber, Card> cards) {
    CardNumber cardNumberForPaired = getCardNumberForCount(2, cards);
    if (cardNumberForPaired != null) {
      List<CardNumber> pairsCardNumber = getPairs(cards);
      if (pairsCardNumber.size() >= 2) {
        return true;
      }
    }
    return false;
  }

  /**
   * 两对中是否有手牌 .
   *
   * @return .
   */
  private boolean isTwoTwoMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempcardsGroup = getNumberGroup(tempCard);
    if (isTwoTwo(cardsGroup) && !isTwoTwo(tempcardsGroup)) {
      return true;
    }
    // if (rank(cards).getHandPowerType() == CardType.TWO_PAIR && rank(tempCard).getHandPowerType()
    // != CardType.TWO_PAIR) {
    // return true;
    // }
    return false;
  }

  /**
   * 是否有三条 .
   *
   * @return .
   */
  private boolean isThree(MapList<CardNumber, Card> cards) {
    CardNumber cardNumberForThree = getCardNumberForCount(3, cards);
    if (cardNumberForThree != null) {
      return true;
    }

    return false;
  }

  /**
   * 三条是否是最大 .
   *
   * @return .
   */
  private boolean isThreeMax(List<Card> cards) {
    return rank(cards).getHandPowerType().getPower() <= CardType.THREE_OF_A_KIND.getPower();
  }

  /**
   * 三条中是否有手牌 .
   *
   * @return .
   */
  private boolean isThreeMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempcardsGroup = getNumberGroup(tempCard);
    if (isThree(cardsGroup) && !isThree(tempcardsGroup)) {
      return true;
    }
    return false;

  }

  /**
   * 是否有四条 .
   *
   * @param cards . .
   * @return .
   */
  private boolean isFour(MapList<CardNumber, Card> cards) {
    CardNumber cardNumberForThree = getCardNumberForCount(4, cards);
    if (cardNumberForThree != null) {
      return true;
    }

    return false;
  }


  /**
   * 四条中是否有手牌 .
   *
   * @param cards . .
   * @param handCards . .
   * @return .
   */
  private boolean isFourMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempcardsGroup = getNumberGroup(tempCard);
    if (isFour(cardsGroup) && !isFour(tempcardsGroup)) {
      return true;
    }
    return false;

  }

  /**
   * 是否有三张顺子 .
   *
   * @return .
   */
  private boolean isLongThree(MapList<CardNumber, Card> cards) {
    CardNumber straightNumber = getStraight(cards, 3);
    if (straightNumber != null) {
      return true;
    }
    return false;
  }

  /**
   * 三张顺子是否有手牌.
   *
   * @return .
   */
  private boolean isLongThreeMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempCardGroup = getNumberGroup(tempCard);
    if (isLongThree(cardsGroup) && !isLongThree(tempCardGroup)) {
      return true;
    }
    return false;
  }

  /**
   * 是否有4张顺子.
   *
   * @return .
   */
  private boolean isLongFour(MapList<CardNumber, Card> cards) {
    CardNumber straightNumber = getStraight(cards, 4);
    if (straightNumber != null) {
      return true;
    }
    return false;
  }

  /**
   * 4张顺子中是否有手牌.
   *
   * @return .
   */
  private boolean isLongFourMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempCardGroup = getNumberGroup(tempCard);
    if (isLongFour(cardsGroup) && !isLongFour(tempCardGroup)) {
      return true;
    }
    return false;
  }

  /**
   * 是否有5张顺子.
   *
   * @return .
   */
  private boolean isLongFive(MapList<CardNumber, Card> cards) {
    CardNumber straightNumber = getStraight(cards, 5);
    if (straightNumber != null) {
      return true;
    }
    return false;
  }

  /**
   * 5张顺子中是否有手牌.
   *
   * @return .
   */
  private boolean isLongFiveMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> cardsGroup = getNumberGroup(cards);
    MapList<CardNumber, Card> tempCardGroup = getNumberGroup(tempCard);
    if (isLongFive(cardsGroup) && !isLongFive(tempCardGroup)) {
      return true;
    }
    return false;
  }

  /**
   * 公牌中是否有3张以上的顺子.
   *
   * @return .
   */

  @SuppressWarnings("unused")
  private boolean isLongFourO(List<Card> cards, List<Card> handCards) {
    List<Card> comonCards = Lists.newArrayList();
    comonCards.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardNumber, Card> numberGroup = getNumberGroup(comonCards);
    CardNumber straightNumber = getStraight(numberGroup, 3);
    if (straightNumber != null) {
      return true;
    }
    return false;
  }

  /**
   * 是否有4张以上的同花.
   *
   * @return .
   */
  private boolean isSameFour(MapList<CardSuit, Card> cards) {
    CardSuit flushSuit = getFlush(cards, 4);
    if (flushSuit != null) {
      return true;
    }
    return false;
  }

  /**
   * 4张以上的同花是否有手牌.
   *
   * @return .
   */
  private boolean isSameFourMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardSuit, Card> suitGroup = getSuitGroup(cards);
    MapList<CardSuit, Card> tempsuitGroup = getSuitGroup(tempCard);
    if (isSameFour(suitGroup) && !isSameFour(tempsuitGroup)) {
      return true;
    }
    return false;
  }

  /**
   * 是否有5张同花.
   *
   * @return .
   */
  private boolean isSameFive(MapList<CardSuit, Card> cards) {
    CardSuit flushSuit = getFlush(cards, 5);
    if (flushSuit != null) {
      return true;
    }
    return false;
  }

  /**
   * 5张同花是否有手牌.
   *
   * @return .
   */
  private boolean isSameFiveMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    MapList<CardSuit, Card> suitGroup = getSuitGroup(cards);
    MapList<CardSuit, Card> tempsuitGroup = getSuitGroup(tempCard);
    if (isSameFive(suitGroup) && !isSameFive(tempsuitGroup)) {
      return true;
    }
    return false;
  }

  /**
   * 是否有同花顺.
   *
   * @return .
   */
  private boolean isSameLong(List<Card> cardList) {
    MapList<CardSuit, Card> suitGroup = getSuitGroup(cardList);// 转成Map结构 花色
    CardNumber straightFlushNumber = getStraightFlushNumber(suitGroup, 5);
    if (straightFlushNumber != null) {
      return true;
    }
    return false;
  }

  /**
   * 同花顺中是否有手牌 .
   *
   * @param cards . .
   * @param handCards . .
   * @return .
   */
  private boolean isSameLongMy(List<Card> cards, List<Card> handCards) {
    List<Card> tempCard = Lists.newArrayList();
    tempCard.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    if (isSameLong(cards) && !isSameLong(tempCard)) {
      return true;
    }
    return false;

  }
}
